package v1

import (
	"github.com/astaxie/beego/validation"
	"github.com/gin-gonic/gin"
	"gitee.com/laofa1/play/k_conf_mng/kconf_backend/models"
	"github.com/unknwon/com"
	"log"
	"net/http"
	"strings"
	"time"
)

type KeyValueType struct {
	Key uint64 `json:"key" binding:""`
	ConfName string `json:"confName"`
	ConfValue string `json:"confValue"`
	Method string `json:"method" binding:"required"`
}

type ColonInstanceType struct {
	OldName string `json:"oldName" binding:"required"`
	NewName string `json:"newName" binding:"required"`
}

type TemplateType struct {
	Content string
}

type TemplateIdType struct {
	ID uint64 `form:"id" binding:"gte=1"`
}

type InstanceID struct {
	ID uint64 `json:"id"`
}

func GetConfItems(c *gin.Context) {
	/**
	@params:
		confName: search in ConfKey.Name
		confType: search equal ConfKey.KeyType
	@return:

	*/

	confName := c.DefaultQuery("confName", "")
	confType := com.StrTo(c.DefaultQuery("confType", "0")).MustInt()

	valid := validation.Validation{}
	valid.Min(confType, 0, "confType").Message("confType不能为负")

	confKeys, err := models.GetConfKeyValueByFilter(confName, uint(confType))
	if err != nil {
		log.Println(err)
		c.JSON(http.StatusOK, gin.H{
			"success": false,
			"message": "",
			"data": make([]models.ConfKeyReal, 0),
		})
		return
	}

	if len(confKeys) == 0 {
		log.Println("get no config items from database")
		c.JSON(http.StatusOK, gin.H{
			"success": true,
			"message": "",
			"data": make([]models.ConfKeyReal, 0),
		})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"success": true,
		"message": "",
		"data": confKeys,
	})
}

func PostConfItems(c *gin.Context) {
	var (
		json KeyValueType
		err error
	)
	if err := c.ShouldBindJSON(&json); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	// process according the method in json
	// userID is set in jwt middleware
	userID := c.MustGet("userID").(uint64)
	code := http.StatusOK
	var errorMessage string
	var successMessage string

	switch json.Method {
	case "post":
		// add new conf key
		if json.ConfName == "" {
			code = http.StatusNotAcceptable
			errorMessage = "confname can't be blank"
		} else {
			confName := strings.ToUpper(json.ConfName)
			if _, err = models.CreateConfKeyValue(confName, json.ConfValue, uint64(userID)); err != nil {
				code = http.StatusBadRequest
				errorMessage =  err.Error()
			} else {
				code = http.StatusOK
				successMessage = "OK"
			}
		}
	case "update":
		if json.Key == 0 {
			code = http.StatusNotAcceptable
			errorMessage = "to update conf value should contain keyid"
		} else {
			if _, err = models.UpdateConfItem(json.Key, userID, json.ConfValue); err != nil {
				code = http.StatusBadRequest
				errorMessage = err.Error()
			} else {
				code = http.StatusOK
				successMessage = "update conf value OK"
			}
		}
	case "delete":
		if json.Key == 0 {
			code = http.StatusNotAcceptable
			errorMessage = "to delete a conf key should provide the conf key id"
		} else {
			if err = models.DeleteConfKey(json.Key); err != nil {
				code = http.StatusBadRequest
				errorMessage = err.Error()
			} else {
				code = http.StatusOK
				successMessage = "delete conf key OK"
			}
		}
	default:
		code = http.StatusNotAcceptable
		errorMessage = "action method not known"
	}

	if code != http.StatusOK {
		c.JSON(code, gin.H{"error": errorMessage})
	} else {
		c.JSON(code, gin.H{"success": successMessage})
	}
}

func CloneInstance(c *gin.Context) {
	var colonInstance ColonInstanceType
	if err := c.BindJSON(&colonInstance); err != nil {
		log.Println(err)
		return
	}
	userID := c.MustGet("userID").(uint64)
	if err := models.CloneConfInstance(colonInstance.NewName,
		colonInstance.OldName, userID); err != nil {
			log.Println(err)
			c.JSON(http.StatusBadRequest, gin.H{
				"error": "clone instance fail",
			})
			return
	}
	c.JSON(http.StatusOK, gin.H{"success": "clone instance OK"})
}

func GetInstances(c *gin.Context) {
	// test goroutine
	go func() {

		time.Sleep(time.Second * 3)
		log.Println("finish after sleep 10 second")
	}()

	if instances, err := models.GetInstances(); err != nil {
		log.Println(err)
		c.JSON(http.StatusBadRequest, gin.H{
			"status": "fail", "message": err.Error(),
		})
		return
	} else {
		c.JSON(http.StatusOK, gin.H{
			"data": instances,
		})
	}
}

func RemoveInstance(c *gin.Context) {
	var instanceID InstanceID
	if err := c.BindJSON(&instanceID); err != nil {
		log.Println(err)
		return
	}
	if err := models.DeleteInstance(instanceID.ID); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"status": "fail", "message": err.Error(),
		})
		return
	} else {
		c.JSON(http.StatusOK, gin.H{
			"status": "ok", "message": "",
		})
	}
}

func GetLastTemplate(c *gin.Context) {
	if content, err := models.GetConfTemplateContent("testing"); err != nil {
		log.Println(err)
		c.JSON(http.StatusOK, gin.H{"content": ""})
		return
	} else {
		c.JSON(http.StatusOK, gin.H{"content": content})
	}
}

func UpdateTemplate(c *gin.Context) {
	var template TemplateType
	if err := c.BindJSON(&template); err != nil {
		log.Println(err)
		return
	}

	userID := c.MustGet("userID").(uint64)

	if err := models.AddorUpdateConfTemplate("testing", template.Content, userID); err != nil {
		log.Println(err)
		c.JSON(http.StatusBadRequest, gin.H{"error": "add or update template content error"})
		return
	} else {
		c.JSON(http.StatusOK, gin.H{"success": "add or update template content OK"})
	}
}

func GetAllTemplate(c *gin.Context) {
	err, templateList := models.GetTemplateList()
	if err != nil {
		log.Println(err.Error())
		c.String(http.StatusBadRequest, "")
		return
	}
	c.JSON(http.StatusOK, gin.H{
		"status": "ok",
		"data": templateList,
	})
}

func GetTemplateById(c *gin.Context) {
	var templateID TemplateIdType
	if err := c.BindQuery(&templateID); err != nil {
		log.Println(err.Error())
		return
	}
	if confTemplate, err := models.GetTemplateById(templateID.ID); err != nil {
		log.Println(err.Error())
		c.JSON(http.StatusOK, gin.H{
			"status": "fail",
			"message": err.Error(),
		})
		return
	} else {
		c.JSON(http.StatusOK, gin.H{
			"status": "ok",
			"data": confTemplate,
		})
	}

}

